#pragma once

#include <brpc/server.h>
#include <butil/logging.h>

#include "etcd.hpp"
#include "utils.hpp"
#include "logger.hpp"
#include "base.pb.h"
#include "file.pb.h"

namespace xu
{
    class FileServicelmpl :public xu::FileService
    {
    public:
        FileServicelmpl(const std::string & data_path)
        :_data_path(data_path)
        {
            umask(0);
            mkdir(_data_path.c_str(),0775);
            if(_data_path.back() != '/') _data_path.push_back('/');
        }
        ~FileServicelmpl(){}

        virtual void GetSingleFile(::google::protobuf::RpcController* controller,
                       const ::xu::GetSingleFileReq* request,
                       ::xu::GetSingleFileRsp* response,
                       ::google::protobuf::Closure* done)  override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            //1.获取文件名
            
            std::string filename = _data_path + request->file_id();


            //2.获取文件数据
            std::string body;
            if(ReadFile(filename,body) == false)
            {
                LOG_ERROR("请求{}: 文件失败",filename);
                response->set_success(false);
                response->set_errmsg("请求数据失败");
                return;
            }
            //3.组织响应
            response->set_success(true);
            response->set_errmsg("");
            response->mutable_file_data()->set_file_id(request->file_id());
            response->mutable_file_data()->set_file_content(body);
            LOG_INFO("下载单文件完成");
        }
        virtual void GetMultiFile(::google::protobuf::RpcController* controller,
                       const ::xu::GetMultiFileReq* request,
                       ::xu::GetMultiFileRsp* response,
                       ::google::protobuf::Closure* done)  override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id());
            //1.遍历file_id,进行文件读取
            for(int i = 0; i < request->file_id_list_size(); ++i)
            {
                //1.1获取当个文件内容
                LOG_DEBUG("file_id: {} ",request->file_id_list(i));
                std::string filename =  _data_path + request->file_id_list(i);
                std::string body;
                if(ReadFile(filename,body) == false)
                {
                    LOG_ERROR("请求{}: 文件失败",filename);
                    response->set_success(false);
                    response->set_errmsg("请求数据失败");
                    return;
                }
                //1.2组织单个文件信息
                FileDownloadData file_down_data;
                file_down_data.set_file_id(request->file_id_list(i));
                file_down_data.set_file_content(body);
                response->mutable_file_data()->insert({request->file_id_list(i),file_down_data});
            }
            //2.组织响应
            response->set_success(true);
            LOG_INFO("下载多文件完成");
        }
        virtual void PutSingleFile(::google::protobuf::RpcController* controller,
                       const ::xu::PutSingleFileReq* request,
                       ::xu::PutSingleFileRsp* response,
                       ::google::protobuf::Closure* done)  override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id());
            //1.创建文件名
            std::string file_id = uuid();
            std::string filename = _data_path +  file_id;
            //2.写入数据
            if(WriteFile(filename,request->file_data().file_content()) == false)
            {
                LOG_ERROR("上传{}: 文件失败",filename);
                response->set_success(false);
                response->set_errmsg("上传数据失败");
                return;
            }
            //3.组织响应
            response->set_success(true);
            response->set_errmsg("");
            response->mutable_file_info()->set_file_id(file_id);
            response->mutable_file_info()->set_file_size(request->file_data().file_size());
            response->mutable_file_info()->set_file_name(request->file_data().file_name());
            LOG_INFO("完成单文件上传");
        }
        virtual void PutMultiFile(::google::protobuf::RpcController* controller,
                       const ::xu::PutMultiFileReq* request,
                       ::xu::PutMultiFileRsp* response,
                       ::google::protobuf::Closure* done)  override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id());
            //1.创建批量文件名
            for(int i = 0; i < request->file_data_size(); ++i)
            {
                std::string file_id = uuid();
                std::string filename = _data_path +  file_id;
                //2.写入数据
                if(WriteFile(filename,request->file_data(i).file_content()) == false)
                {
                    LOG_ERROR("上传{}: 文件失败",filename);
                    response->set_success(false);
                    response->set_errmsg("上传数据失败");
                    return;
                }
                //3.组织单个信息
                FileMessageInfo * file_msg_info = response->add_file_info();
                file_msg_info->set_file_id(file_id);
                file_msg_info->set_file_size(request->file_data(i).file_size());
                file_msg_info->set_file_name(request->file_data(i).file_name());
            }
           
            response->set_success(true);
            response->set_errmsg("");
            LOG_INFO("完成多文件上传");
        }
    private:
        std::string _data_path;
    };

    class FileServer
    {
    public:
        using ptr = std::shared_ptr<FileServer>;
        FileServer(xu::Registration::ptr reg,std::shared_ptr<brpc::Server> server)
            :_reg(reg),
            _server(server)
        {}
        ~FileServer(){}
        void Start()
        {
            _server->RunUntilAskedToQuit();
        }
    private:
        xu::Registration::ptr _reg;
        std::shared_ptr<brpc::Server> _server;
    };

    class FileServerBuilder
    {
    public:
        FileServerBuilder(){}
        ~FileServerBuilder(){}

        void SetRcpReg(const std::string &host,const std::string &service_name,
            const std::string &access_host)
        {
            _reg = std::make_shared<Registration>(host);
            _reg->AddKV(service_name,access_host);
        }
        void SetRpcServer(uint16_t port, int32_t timeout, uint8_t num_threads,
            const std::string & base_path)
        {
            _server = std::make_shared<brpc::Server>();

            FileServicelmpl *fileservice = new  FileServicelmpl(base_path);
            _server->AddService(fileservice,brpc::ServiceOwnership::SERVER_OWNS_SERVICE);

            brpc::ServerOptions options;
            options.idle_timeout_sec = timeout;
            options.num_threads = num_threads;

            _server->Start(port, &options);
        }
        FileServer::ptr Build()
        {
            if(!_reg)
            {
                LOG_ERROR("RcpReg未初始化");
                return FileServer::ptr();
            }

            if(!_server)
            {
                LOG_ERROR("RpcServer未初始化");
                return FileServer::ptr();
            }

            auto res = std::make_shared<FileServer>(_reg,_server);
            return res;
        }

    private:
        xu::Registration::ptr _reg;
        std::shared_ptr<brpc::Server> _server;
    };
}
